// ----------------------------------------------------------------------------
// reflection.h
// ----------------------------------------------------------------------------
/* status : 勉強中... 
 Description:
 RTTIを使わない簡易リフレクションの実装. 
 */
#pragma once
#include <vector>
#include <list>
#include <map>
#include <set>
#include <string>
#include <sstream>
#include <ctype.h>
#include <string.h>
#include <fw/base/core/macros.h>
#include <fw/base/core/assertion.h>

#define SERIALIZE_MAX_BLOCK_SIZE (32*1024*1024)

namespace fw
{
    //! シリアライズ用メンバ変数の定義用マクロ. 
    #define DECLARE_MEMBERS(type, members) \
        typedef type self_t; \
        static FW_FORCE_INLINE fw::TypeInfoInterface const& MemberInfo() \
        { \
            static fw::Member data[] = \
            {  \
                members \
            }; \
            static fw::TypeInfo< type > info( \
                data, \
                sizeof(data)/sizeof(data[0]), \
                fw::StructureAccess< type >::GetInstance()); \
            return info; \
        }
 
    #define MEMBER(name) \
        fw::MemberInstance(&self_t::name, #name)
 
    struct Member;
    struct MemberAccessBase;
    
    struct Stream
    {
        virtual size_t          BytesLeft()=0;
        virtual void            ReadBytes (size_t count, void* dest)=0;
        virtual void            WriteBytes(size_t count, void* src) =0;
        virtual size_t          Position()=0;
        virtual void            SetPosition(size_t pos)=0;
    }; // struct BinaryStream 
    
    void WriteBlock         (size_t  length, void const* data, Stream& stream);
    void ReadBlockLength    (size_t& length, Stream& stream);
    void ReadBlockData      (size_t  length, void*       data, Stream& stream);
    
    template< typename T, bool HasMemberInfo > struct Marshal;
    template< typename T, bool HasMemberInfo > struct Convert;
    
    FW_FORCE_INLINE static void QuoteString(char const* instr, std::string& outstr)
    {
        outstr.push_back('\"');
        while(*instr)
        {
            if(*instr=='\"' || *instr=='\\')
            {
                outstr.push_back('\\');
            }
            outstr.push_back(*instr);
            ++instr;
        }
        outstr.push_back('\"');
    }
    
    FW_FORCE_INLINE static char const* UnquoteString(char const* instr, std::string& outstr)
    {
        if (*instr != '\"')
        {
            FW_PRINTF("badly formatted string in UnquoteString (not quoted)");
            return instr;
        }
        ++instr;
        while (true)
        {
            if (*instr == 0)
            {
                FW_PRINTF("badly formatted string in UnquoteString (early end)");
                return instr;
            }
            else if (*instr == '\\')
            {
                if (instr[1] == 0)
                {
                    FW_PRINTF("badly formatted string in UnquoteString (quoted nul)");
                    return instr;
                }
                ++instr;
                outstr.push_back(*instr);
            }
            else if (*instr == '\"')
            {
                ++instr;
                break;
            }
            else
            {
                outstr.push_back(*instr);
            }
            ++instr;
        }
        return instr;        
    }
    
    //------------------------------------------------------------------------------------
    
    //! 
    struct CollectionInfoBase
    {
    public:
        virtual size_t              Size(void const* coll) const = 0;
        virtual bool                BeginIteration(void const* coll,
                                                   void*& oPtr,
                                                   void*& oEnd,
                                                   MemberAccessBase& oAccess) const = 0;
        virtual void                GetElement  (void*& iPtr, void*& oMem) const = 0;
        virtual bool                Increment   (void*& iPtr, void*& iEnd) const = 0;
        virtual void                Cleanup     (void*& iPtr, void*& iEnd) const = 0;
        virtual void                Clear       (void* coll)               const = 0;
        virtual void                AppendFrom  (void* coll, Stream& iStr) const = 0;
        virtual char const*         AppendFrom  (void* coll, char const* str) const = 0;
    }; // struct CollectionInfoBase 
    
    //! 型情報にアクセスするためのベースクラス. 
    struct TypeInfoBase
    {
    protected:
        Member const*               m_members;
        size_t                      m_count;
        MemberAccessBase const&     m_access;
    public:
        TypeInfoBase(Member const* members, size_t count, MemberAccessBase& access)
        : m_members (members)
        , m_count   (count)
        , m_access  (access)
        {
        }
        
        FW_FORCE_INLINE Member const*   Begin() const;
        FW_FORCE_INLINE Member const*   End()   const;
        FW_FORCE_INLINE MemberAccessBase const&  Access() const
        {
            return m_access;
        }
        
    }; // struct TypeInfoBase 
    
    //! メンバーにアクセスするためのベースクラス. 
    struct MemberAccessBase
    {
    private:
        size_t                      m_memSize;
        size_t                      m_offset;
        TypeInfoBase const*         m_base;
        CollectionInfoBase const*   m_collection;

        virtual void                DoGetFrom  (void const* strct, Stream& oStr)      const = 0;
        virtual void                DoPutTo    (void*       strct, Stream& iStr)      const = 0;
        virtual void                DoToText   (void const *strct, std::string& oStr) const = 0;
        virtual char const*         DoFromText (void *strct, char const *str)         const = 0;
        
    public:
        
        MemberAccessBase(size_t                     memSize,
                         size_t                     offset,
                         TypeInfoBase const*        base,
                         CollectionInfoBase const*  collection)
        : m_memSize     (memSize)
        , m_offset      (offset)
        , m_base        (base)
        , m_collection  (collection)
        {
        }
        
        FW_FORCE_INLINE void        GetFrom     (void const* strct, Stream& oStr) const;
        FW_FORCE_INLINE void        PutTo       (void *strct, Stream &iStr) const;
        FW_FORCE_INLINE void        ToText      (void const *strct, std::string &oStr) const;
        FW_FORCE_INLINE char const* FromText    (void *strct, char const *str) const;
        
        FW_FORCE_INLINE size_t      Size()      const { return m_memSize;  }
        FW_FORCE_INLINE size_t      Offset()    const { return m_offset;   }
        FW_FORCE_INLINE bool        Compound()  const { return(m_base!=0); }
        FW_FORCE_INLINE TypeInfoBase const& MemberInfo() const
        {
            return *m_base;
        }
        FW_FORCE_INLINE bool        Collection() const
        {
            return (m_collection!=0);
        }
        FW_FORCE_INLINE CollectionInfoBase const& CollectionInfo() const
        {
            FW_ASSERT(m_collection);
            return *m_collection;
        }
        virtual void                Create  (void *ptr) const = 0;
        virtual void                Destroy (void *ptr) const = 0;
        
    }; // struct MemberAccessBase 
    
    //! メンバーのアノテーションを表示する. 
    struct MemberInfoBase
    {
    protected:
        char const* m_desc;
    public:
        MemberInfoBase(char const *desc)
        : m_desc(desc)
        {
        }
        FW_FORCE_INLINE char const* Desc() const
        {
            return m_desc;
        }
    }; // struct MemberInfoBase   
    
    //! メンバ変数を代表するクラス. 
    struct Member
    {
    protected:
        char const*         m_name;
        MemberAccessBase&   m_access;
        MemberInfoBase&     m_info;
    public:
        typedef Member const *Iterator;
        
        Member(char const* name, MemberAccessBase& access, MemberInfoBase& info)
        : m_name    (name)
        , m_access  (access)
        , m_info    (info)
        {
        }
    
        FW_FORCE_INLINE char const* Name() const
        {
            return m_name;
        }
        
        FW_FORCE_INLINE MemberAccessBase const& Access() const
        {
            return m_access;
        }
        
        FW_FORCE_INLINE MemberInfoBase const& Info() const
        {
            return m_info;
        }
        
    }; // struct Member 
    
    template<typename Member> struct TypeInfo : public TypeInfoBase
    {
        TypeInfo(Member const* ptr, size_t cnt, MemberAccessBase const& mab)
		: TypeInfoBase(ptr, cnt, mab)
        {
        }
    }; // struct TypeInfo 

    template<typename T> struct HasMemberInfo
    {
        template<int N> struct bar
		{
			char x[N];
        };
        template<typename Q> static inline char sfinae(Q* t, bar<sizeof(&Q::MemberInfo)>* u)
		{
			return sizeof(*u);
		}
        static inline int sfinae(...)
		{
			return 4;
		}
        enum
		{
			value = (1 == sizeof(sfinae((T*)0)))
		};
    }; // struct HasMemberInfo 
	
    template<typename MemT, bool HasMemberInfo> struct GetMemberInfoBase;
	
    template<typename MemT> struct GetMemberInfoBase<MemT, false>
    {
        static inline TypeInfoBase const* Info()
		{
			return 0;
		}
    }; // struct GetMemberInfoBase 
	
    template<typename MemT> struct GetMemberInfoBase<MemT, true>
    {
        static inline TypeInfoBase const* Info()
		{
			return &MemT::MemberInfo();
		}
    }; // struct GetMemberInfoBase 
	
    template<typename MemT> struct GetMemberInfo
	: GetMemberInfoBase<MemT, HasMemberInfo<MemT>::value>
    {
    }; // struct GetMemberInfo 
	
    template<typename MemT> struct GetCollectionInfo
    {
        enum
		{
			isCollection = 0
		};
        static inline CollectionInfoBase const* Info()
		{
			return 0;
		}
    }; // GetCollectionInfo 
    
    template<typename Coll> struct Collection : public CollectionInfoBase
    {
        inline static Collection& Instance()
        {
            static Collection collectionInstance;
            return collectionInstance;
        }
        virtual size_t Size(void const* coll) const
        {
            return ((Coll const *)coll)->Size();
        }
        template<typename MemT> struct IterDeref : MemberAccessBase
        {
            IterDeref() :
			MemberAccessBase(sizeof(MemT),
							 0, 
							 GetMemberInfo    <MemT>::Info(),
							 GetCollectionInfo<MemT>::Info())
            {
            }
            virtual void Create (void* ptr) const
            {
                new (ptr) MemT;
            }
            virtual void Destroy(void* ptr) const
            {
                ((MemT *)ptr)->~MemT();
            }
            virtual void DoGetFrom(void const* strct, Stream& oStr) const
            {
                Marshal<MemT, HasMemberInfo<MemT>::value>::Output(*(MemT const *)strct, oStr);
            }
            virtual void DoPutTo  (void* strct, Stream& iStr) const
            {
                Marshal<MemT, HasMemberInfo<MemT>::value>::Input (*(MemT *)strct,       iStr);
            }
            virtual void DoToText (void const* strct, std::string& oStr) const
            {
                Convert<MemT, HasMemberInfo<MemT>::value>::ToString(*(MemT const *)strct, oStr);
            }
            virtual char const* DoFromText(void* strct, char const* str) const
            {
                return Convert<MemT, HasMemberInfo<MemT>::value>::FromString(*(MemT *)strct, str);
            }
        }; // struct IterDeref 
		
        static inline MemberAccessBase& GetAccess()
        {
            static IterDeref<typename Coll::value_type> access;
            return access;
        }
		
        virtual bool BeginIteration(void const* coll, void*& oPtr, void*& oEnd, MemberAccessBase*& oAccess) const
        {
            oAccess = &GetAccess();
            Coll const &c = *(Coll const *)coll;
            typename Coll::const_iterator ptr(c.begin());
            typename Coll::const_iterator end(c.end());
            if(ptr == end)
            {
                oPtr = 0;
                oEnd = 0;
                return false;
            }
            oPtr = new typename Coll::const_iterator(c.begin());
            oEnd = new typename Coll::const_iterator(c.end());
            return true;
        }
        virtual void GetElement(void* iPtr, void*& oMem) const
        {
            oMem = const_cast<void *>(static_cast<void const *>(&**(typename Coll::const_iterator *)iPtr));
        }
        virtual bool Increment(void*& iPtr, void*& iEnd) const
        {
            if(iPtr == 0 || iEnd == 0)
            {
                return false;
            }
            typename Coll::const_iterator &ptr(*(typename Coll::const_iterator *)iPtr);
            typename Coll::const_iterator &end(*(typename Coll::const_iterator *)iEnd);
            ++ptr;
            if (ptr == end)
            {
                Cleanup(iPtr, iEnd);
                return false;
            }
            return true;
        }
        virtual void Cleanup(void*& iPtr, void*& iEnd) const
        {
            if(iPtr != 0)
            {
                delete (typename Coll::const_iterator *)iPtr;
                iPtr = 0;
            }
            if(iEnd != 0)
            {
                delete (typename Coll::const_iterator *)iEnd;
                iEnd = 0;
            }
        }
        virtual void Clear(void *coll) const
        {
            ((Coll *)coll)->clear();
        }
        template<typename T> struct Insert
        {
            static inline void Func(void* coll, typename T::value_type const& vt)
            {
                (*(Coll *)coll).push_back(vt);
            }
        };
        template<typename T> struct Insert< std::set<T> >
        {
            static inline void Func(void* coll, typename T::value_type const& vt)
            {
                (*(std::set<T> *)coll).insert(vt);
            }
        };
        virtual void AppendFrom(void* coll, Stream& iStr) const
        {
            typename Coll::value_type  tmp;
            GetAccess().PutTo(&tmp, iStr);
            Insert<Coll>::Func(coll, tmp);
        }
        virtual char const* AppendFrom(void* coll, char const* str) const
        {
            typename Coll::value_type tmp;
            str = GetAccess().FromText(&tmp, str);
            Insert<Coll>::Func(coll, tmp);
            return str;
        }
    }; // struct Collection 
    
    template<typename MemT> struct GetCollectionInfo< std::list<MemT> >
    {
        enum 
		{
			isCollection = 1
		};
        static inline CollectionInfoBase const* Info()
		{
            return &Collection< std::list<MemT> >::Instance();
        }
    };
	
    template<typename MemT> struct GetCollectionInfo< std::vector<MemT> >
    {
        enum
		{
			isCollection = 1
		};
        static inline CollectionInfoBase const *Info()
		{
            return &Collection< std::vector<MemT> >::Instance();
        }
    };
	
    template<typename MemT> struct GetCollectionInfo< std::set<MemT> >
    {
        enum
		{
			isCollection = 1
		};
        static inline CollectionInfoBase const *Info()
		{
            return &Collection< std::set<MemT> >::Instance();
        }
    };
	
    template<typename Struct, typename MemT, bool IsCollection> struct MemberAccess;
    template<typename Struct, typename MemT>
    struct MemberAccess<Struct, MemT, false> : public MemberAccessBase
    {
    protected:
        MemT Struct::*m_member;
	public:
        MemberAccess(MemT Struct::*member)
		: MemberAccessBase( sizeof(MemT), 
						   (char *)&(((Struct *)0)->*member) - (char *)0,
						   GetMemberInfo<MemT>::Info(),
						   GetCollectionInfo<MemT>::Info())
		, m_member(member)
        {
        }
        virtual void Create(void* ptr) const
        {
            new (ptr) MemT;
        }
        virtual void Destroy(void* ptr) const
        {
            ((MemT *)ptr)->~MemT();
        }
        virtual void DoGetFrom(void const* strct, Stream& oStr) const
        {
            Marshal<MemT, HasMemberInfo<MemT>::value>::Output(((Struct const *)strct)->*m_member, oStr);
        }
        virtual void DoPutTo(void *strct, Stream &iStr) const
        {
            Marshal<MemT, HasMemberInfo<MemT>::value>::Input(((Struct *)strct)->*m_member, iStr);
        }
        virtual void DoToText(void const *strct, std::string &oStr) const
        {
            Convert<MemT, HasMemberInfo<MemT>::value>::ToString(((Struct const *)strct)->*m_member, oStr);
        }
        virtual char const *DoFromText(void *strct, char const *str) const
        {
            return Convert<MemT, HasMemberInfo<MemT>::value>::FromString(((Struct *)strct)->*m_member, str);
        }
        inline MemT Struct::*Member() const { return m_member; }
    }; // struct MemberAccess 
	
	template<typename Struct, typename MemT>
	struct MemberAccess<Struct, MemT, true> : public MemberAccessBase
	{
	protected:
		MemT Struct::*m_member;
	public:
		MemberAccess(MemT Struct::*member)
		: MemberAccessBase( sizeof(MemT),
						   (char*)&(((Struct *)0)->*member) - (char *)0,
						   GetMemberInfo<MemT>::Info(),
						   GetCollectionInfo<MemT>::Info())
		, m_member(member)
		{
		}
		virtual void Create(void* ptr) const
		{
			new (ptr) MemT;
		}
		virtual void Destroy(void* ptr) const
		{
			((MemT*)ptr)->~MemT();
		}
        virtual void DoGetFrom(void const *strct, Stream &oStr) const
        {
            FW_PRINTF("DoGetGrom() on struct");
        }
        virtual void DoPutTo(void *strct, Stream &iStr) const
        {
            FW_PRINTF("DoPutTo() on struct");
        }
        virtual void DoToText(void const *strct, std::string &oStr) const
        {
			FW_PRINTF("DoToText() on struct");
        }
        virtual char const *DoFromText(void *strct, char const *str) const
        {
            FW_PRINTF("DoFromText() on struct");
        }
        inline MemT Struct::*member() const { return m_member; }
	}; // struct MemberAccess
    
	template<typename MemT> struct StructAccess : public MemberAccessBase
	{
	public:
		StructAccess()
		: MemberAccessBase(sizeof(MemT),
						   0,
						   GetMemberInfo<MemT>::Info(),
						   0)
		{
		}
		virtual void Create(void* ptr) const
		{
			new (ptr) MemT;
		}
		virtual void Destroy(void* ptr) const
		{
			((MemT*)ptr)->~MemT();
		}
        virtual void DoGetFrom(void const *strct, Stream &oStr) const
        {
            Marshal<MemT, true>::Output(*(MemT const *)strct, oStr);
        }
        virtual void DoPutTo(void *strct, Stream &iStr) const
        {
            Marshal<MemT, true>::Input(*(MemT *)strct, iStr);
        }
        virtual void DoToText(void const *strct, std::string &oStr) const
        {
            Convert<MemT, true>::ToString(*(MemT const *)strct, oStr);
        }
        virtual char const *DoFromText(void *strct, char const *str) const
        {
            return Convert<MemT, true>::FromString(*(MemT *)strct, str);
        }
		static StructAccess& Instance()
		{
			static StructAccess access;
			return access;;
		}
	}; // struct StructAccess 
	
    template<typename Struct, typename Item> struct MemberAccess<Struct, Item const *, false>;
    template<typename Struct, typename Item> struct MemberAccess<Struct, Item *, false>;

    template<typename Desc> char const *GetDesc(Desc const &str) { return Desc::GetDesc(str); }

    FW_FORCE_INLINE char const* GetDesc(char const *const &str) { return str; }
    FW_FORCE_INLINE char const* GetDesc(std::string const &str) { return str.c_str(); }

	template<typename Description> class MemberInfoT : MemberInfoBase
    {
        MemberInfoT(Description const &desc)
		: MemberInfoBase(GetDesc(desc))
        {
        }
    };

    template<typename Description, typename Struct, typename MemT> MemberInfoBase* MemberInfo(Description const &desc)
    {
        return new MemberInfoT<Description>(desc);
    }
	
    template<typename Struct, typename MemT, typename Desc>
	Member MemberInstance(MemT Struct::*member, char const *name, Desc const &desc)
    {
        return Member(name,
					  *new MemberAccess<Struct, MemT, GetCollectionInfo<MemT>::is_collection>(member),
					  *MemberInfo<Desc, Struct, MemT>(desc));
    }
	
    template<typename T> struct Range
    {
        Range(char const *text, T const &low, T const &high)
		: m_text (text)
		, m_low  (low)
		, m_high (high)
        {
        }
        char const*		m_text;
        T				m_low;
        T				m_high;
        static inline char const* Get_desc(Range const &r) { return r.text_; }
    };
    typedef Range<int> IntRange;
	
	
	
	
	
	
    
    FW_FORCE_INLINE Member const* TypeInfoBase::Begin() const
    {
        return m_members;
    }
    
    FW_FORCE_INLINE Member const* TypeInfoBase::End()   const
    {
        return m_members + m_count;
    }
    
} // namespace fw 

#define SERIALIZE(type, members) \
    typedef type self_t; \
    static FW_FORCE_INLINE 

